/**
 * @author        Nicolas Bottarini <nicolasbottarini@gmail.com>, 404 <http://www.proyecto404.com>
 * @version       $Rev: 3 $
 * @lastrevision  $Date: 2011-09-12 16:45:37 +0000 (Mon, 12 Sep 2011) $	 
 */
package com.proyecto404.core.mvc {
	import com.proyecto404.core.AssetInfo;
	import com.proyecto404.core.AssetInfoTypes;
	import com.proyecto404.core.BaseObject;
	import com.proyecto404.core.EventArgs;
	import com.proyecto404.core.collections.IIterator;
	import com.proyecto404.core.collections.KeyValuePair;
	import com.proyecto404.core.collections.List;
	import com.proyecto404.core.collections.Set;
	import com.proyecto404.core.configuration.PreloaderInfo;
	import com.proyecto404.core.exception.AbstractMethodException;
	import com.proyecto404.core.exception.InvalidOperationException;
	import com.proyecto404.core.exception.NotImplementedException;
	import com.proyecto404.core.io.DisplayObjectLoadedEventArgs;
	import com.proyecto404.core.io.MultiAssetLoader;
	import com.proyecto404.core.io.MultiFileLoadProgressEventArgs;
	import com.proyecto404.core.io.SoundLoadedEventArgs;
	import com.proyecto404.core.ui.BaseMovieClip;
	import com.proyecto404.core.util.FileHelper;
	
	import flash.display.Bitmap;
	import flash.errors.IllegalOperationError;
	
	import org.osflash.signals.ISignal;
	import org.osflash.signals.Signal;
	
	public class Preloader extends BaseObject  {
		private var _preloadedCallBack:Function;
		private var _loader:MultiAssetLoader;
		private var _application:Application;
		private var _assetsToLoad:Set;
		private var _hasStarted:Boolean;
		private var _preloaderInfo:PreloaderInfo;
		
		public function Preloader(application:Application, preloaderInfo:PreloaderInfo) {
			_loader = new MultiAssetLoader();
			_assetsToLoad = new Set();
			_hasStarted = false;
			_application = application;
			_preloaderInfo = preloaderInfo;
			
			initialize();
		}
		
		private function initialize():void {
			var assetsIt:IIterator = _preloaderInfo.getAssets();
			var assetInfo:AssetInfo = null;
			while(assetsIt.hasNext()) {
				assetInfo = assetsIt.next();
				addAsset(assetInfo);
			}
			
			var viewsIt:IIterator = _application.configuration["views"];
			while(viewsIt.hasNext()) {
				var viewInfo:ViewInfo = viewsIt.next() as ViewInfo;
				if (viewInfo.preloadedWith == _preloaderInfo.name) {
					assetInfo = new AssetInfo(viewInfo.file, AssetInfoTypes.Swf);
					addAsset(assetInfo);
				}
			}
		}
		
		private function addAsset(assetInfo:AssetInfo):void {
			if (_hasStarted) {
				throw new InvalidOperationException("Cannot add assets while preloader is running");
			}
			
			if (_assetsToLoad.contains(assetInfo.file)) {
				return;
			}
			setLoaderFile(assetInfo);
			_assetsToLoad.add(assetInfo.file);
		}
		
		// Method used because actionScript doesn't have while scope for closures
		private function setLoaderFile(assetInfo:AssetInfo):void {
			_loader.addAsset(assetInfo.file, assetInfo.type, function(e:EventArgs):void { 
				switch(assetInfo.type) {
					case AssetInfoTypes.Swf:
						_application.library.storeSwf(FileHelper.getFileName(assetInfo.file), DisplayObjectLoadedEventArgs(e).content);
						break;
					case AssetInfoTypes.Sound:
						_application.library.storeSound(FileHelper.getFileName(assetInfo.file), SoundLoadedEventArgs(e).sound);
						break;
					case AssetInfoTypes.Bitmap:
						_application.library.storeBitmap(FileHelper.getFileName(assetInfo.file), DisplayObjectLoadedEventArgs(e).content as Bitmap);
						break;
					default:
						throw new IllegalOperationError("Invalid Asset Type");
				}
			});
		}

		
		public function start():void {
			_hasStarted = true;
			_loader.error.add(function(e:EventArgs):void {
				throw new InvalidOperationException("Preloader error: ");
			});
			_loader.loadAll();
		}
		
		public function get allLoaded():ISignal {
			return _loader.allLoaded;
		}
		
		public function get progress():ISignal {
			return _loader.progress;
		}
	}
}